package com.wgtgt.mybatis_gen;

import java.util.ArrayList;
import java.util.List;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.StrUtil;

public class CodeGen {

	public static String gen(String code, String packageName) {
		StringBuilder sb = new StringBuilder();
		if (StrUtil.isBlank(code)) {
			throw new RuntimeException("原始代码不可为空!");
		}
		code = StrUtil.trim(code);
		String comment = "";
		String body = "";
		String tab = "    ";
		String tab2 = tab + tab;
		String tab3 = tab + tab + tab;
		String tab4 = tab + tab + tab + tab;
		String nl = "\n";
		if (code.contains("//")) {
			body = StrUtil.subBefore(code, "//", false);
			comment = StrUtil.subAfter(code, "//", false);
			body = StrUtil.trim(body);
			comment = StrUtil.trim(comment);
			System.out.println("body=" + body);
			System.out.println("comment=" + comment);
			sb.append(tab2);
			sb.append("<!-- ");
			sb.append(comment);
			sb.append(" -->");
			sb.append(nl);
//			sb.append(tab2);
			sb.append(genBody(body, packageName));
			sb.append(nl);
		}
		return sb.toString();
	}

	private static String genBody(String body, String packageName) {
		body = StrUtil.trim(body);
		if (body.endsWith(";")) {
			body = body.substring(0, body.length() - 1);
			int leftBracketsIndex = body.indexOf("(");
			int rightBracketsIndex = body.lastIndexOf(")");
			String nameGroup = body.substring(0, leftBracketsIndex);
			String paramGroup = body.substring(leftBracketsIndex + 1, rightBracketsIndex);
			System.out.println("nameGroup=" + nameGroup);
			System.out.println("paramGroup=" + paramGroup);
			Pair<String, String> decompose = decompose(nameGroup);
			String returnValue = decompose.getKey();
			String methodName = decompose.getValue();
			System.out.println("methodName=" + methodName);
			System.out.println("returnValue=" + returnValue);
			String tagType = tagType(methodName);
			String tagName = tageName(tagType);
			String returnValueType = returnValueType(returnValue, packageName);
			List<String> paramList = paramList(paramGroup);
			String code = null;
			if ("select".equals(tagType)) {
				code = codeGen(tagType, tagName, methodName, returnValueType, paramGroup, paramList, packageName);
			} else if ("insert".equals(tagType)) {
				code = codeGenInsert(tagType, tagName, methodName, returnValueType, paramGroup, paramList, packageName);
			} else if ("update".equals(tagType)) {
				code = codeGenUpdate(tagType, tagName, methodName, returnValueType, paramGroup, paramList, packageName);
			} else if ("delete".equals(tagType)) {
				code = codeGenDelete(tagType, tagName, methodName, returnValueType, paramGroup, paramList, packageName);
			}
			return code;
		}
		return null;
	}

	private static String codeGen(String tagType, String tagName, String methodName, String returnValueType,
			String paramGroup, List<String> paramList, String packageName) {
		String tab = "    ";
		String tab2 = tab + tab;
		String tab3 = tab + tab + tab;
		String tab4 = tab + tab + tab + tab;
		String nl = "\n";
		StringBuilder sb = new StringBuilder();
		sb.append(tab2 + "<");
		sb.append(tagName);
		sb.append(" id = \"");
		sb.append(methodName);
		sb.append("\"");
		sb.append(paramSpanTypeOut(paramGroup, packageName));
		sb.append(resultTypeCode(returnValueType, packageName));
		sb.append(">");
		sb.append(nl);
		for (int i = 0; i < paramList.size(); i++) {
			String string = paramList.get(i);
			sb.append(tab3);
			sb.append("#{");
			sb.append(string);
			sb.append("}");
			sb.append(nl);
		}
		sb.append(tab2 + "<");
		sb.append(tagName);
		sb.append("/>");
		return sb.toString();
	}

	private static String paramSpanTypeOut(String paramGroup, String packageName) {
		if (paramGroup == null) {
			throw new RuntimeException("需要解析的参数不能为空!");
		}
		paramGroup = StrUtil.trim(paramGroup);
		List<String> list = new ArrayList<String>();
		if ("".equals(paramGroup)) {
			return "";
		}
		String[] split = paramGroup.split(",");
		for (int i = 0; i < split.length; i++) {
			String paramSpan = paramSpanType(split[i]);
			list.add(paramSpan);
		}
		return wrapParamSpan(list.get(0), packageName);
	}

	private static String wrapParamSpan(String string, String packageName) {
		return " " + wrapParamSpanWithTag(string, packageName);
	}

	private static String wrapParamSpanWithTag(String string, String packageName) {
		return "parameterType = \"" + wrapParamSpanWithPackageName(string, packageName) + "\"";
	}

	private static String wrapParamSpanWithPackageName(String string, String packageName) {
		if ("void".equals(string)) {
			return "void";
		}
		if ("int".equals(string)) {
			return "java.lang.Integer";
		}
		if ("double".equals(string)) {
			return "java.lang.Double";
		}
		if ("String".equals(string)) {
			return "java.lang.String";
		}
		if ("Date".equals(string)) {
			return "java.util.Date";
		}
		if ("List".equals(string)) {
			return "java.util.List";
		}
		if ("Set".equals(string)) {
			return "java.util.Set";
		}
		if ("Map".equals(string)) {
			return "java.util.Map";
		}
		return packageName + "." + string;
	}

	private static String resultTypeCode(String returnValueType, String packageName) {
		if ("void".equals(returnValueType)) {
			return "";
		}
		return " " + resultTypeCodeDetail(wrapParamSpanWithPackageName(returnValueType, packageName));
	}

	private static String resultTypeCodeDetail(String resultType) {
		return "resultType = \"" + resultType + "\"";
	}

	private static String codeGenInsert(String tagType, String tagName, String methodName, String returnValueType,
			String paramGroup, List<String> paramList, String packageName) {
		String tab = "    ";
		String tab2 = tab + tab;
		String tab3 = tab + tab + tab;
		String tab4 = tab + tab + tab + tab;
		String nl = "\n";
		StringBuilder sb = new StringBuilder();
		sb.append(tab2 + "<");
		sb.append(tagName);
		sb.append(" id = \"");
		sb.append(methodName);
		sb.append("\"");
		sb.append(paramSpanTypeOut(paramGroup, packageName));
		sb.append(" useGeneratedKeys=\"true\" keyProperty=\"id\"");
		sb.append(">");
		sb.append(nl);
		for (int i = 0; i < paramList.size(); i++) {
			String string = paramList.get(i);
			sb.append(tab3);
			sb.append("#{");
			sb.append(string);
			sb.append("}");
			sb.append(nl);
		}
		sb.append(tab2 + "<");
		sb.append(tagName);
		sb.append("/>");
		return sb.toString();
	}

	private static String codeGenUpdate(String tagType, String tagName, String methodName, String returnValueType,
			String paramGroup, List<String> paramList, String packageName) {
		String tab = "    ";
		String tab2 = tab + tab;
		String tab3 = tab + tab + tab;
		String tab4 = tab + tab + tab + tab;
		String nl = "\n";
		StringBuilder sb = new StringBuilder();
		sb.append(tab2 + "<");
		sb.append(tagName);
		sb.append(" id = \"");
		sb.append(methodName);
		sb.append("\"");
		sb.append(">");
		sb.append(nl);
		for (int i = 0; i < paramList.size(); i++) {
			String string = paramList.get(i);
			sb.append(tab3);
			sb.append("#{");
			sb.append(string);
			sb.append("}");
			sb.append(nl);
		}
		sb.append(tab2 + "<");
		sb.append(tagName);
		sb.append("/>");
		return sb.toString();
	}

	private static String codeGenDelete(String tagType, String tagName, String methodName, String returnValueType,
			String paramGroup, List<String> paramList, String packageName) {
		String tab = "    ";
		String tab2 = tab + tab;
		String tab3 = tab + tab + tab;
		String tab4 = tab + tab + tab + tab;
		String nl = "\n";
		StringBuilder sb = new StringBuilder();
		sb.append(tab2 + "<");
		sb.append(tagName);
		sb.append(" id = \"");
		sb.append(methodName);
		sb.append("\"");
		sb.append(">");
		sb.append(nl);
		for (int i = 0; i < paramList.size(); i++) {
			String string = paramList.get(i);
			sb.append(tab3);
			sb.append("#{");
			sb.append(string);
			sb.append("}");
			sb.append(nl);
		}
		sb.append(tab2 + "<");
		sb.append(tagName);
		sb.append("/>");
		return sb.toString();
	}

	private static String returnValueType(String returnValue, String packageName) {
		if (StrUtil.isBlank(returnValue)) {
			throw new RuntimeException("返回值无法解析!");
		}
		returnValue = StrUtil.trim(returnValue);
		if ("void".equals(returnValue)) {
			return "void";
		}
		if ("int".equals(returnValue)) {
			return "java.lang.Integer";
		}
		if ("double".equals(returnValue)) {
			return "java.lang.Double";
		}
		if ("String".equals(returnValue)) {
			return "java.lang.String";
		}
		if ("Date".equals(returnValue)) {
			return "java.util.Date";
		}
		String simpleTypeName = "";
		if (returnValue.contains("<") && returnValue.contains(">")) {
			if (returnValue.startsWith("Map")) {
				return "java.util.Map";
			}
			if (returnValue.startsWith("List")) {
				int leftIndex = returnValue.indexOf("<");
				int rightIndex = returnValue.lastIndexOf(">");
				String type = returnValue.substring(leftIndex + 1, rightIndex);
				simpleTypeName = type;
			}
		} else {
			if (returnValue.contains(" ")) {
				simpleTypeName = StrUtil.subAfter(returnValue, " ", true);
			} else {
				simpleTypeName = returnValue;
			}
		}
		return simpleTypeName;
	}

	private static String tageName(String tagType) {
		if ("delete".equals(tagType)) {
			return "update";
		}
		return tagType;
	}

	private static String tagType(String methodName) {
		if (StrUtil.isBlank(methodName)) {
			return "select";
		} else if (methodName.startsWith("select")) {
			return "select";
		} else if (methodName.startsWith("query")) {
			return "select";
		} else if (methodName.startsWith("find")) {
			return "select";
		} else if (methodName.startsWith("check")) {
			return "select";
		} else if (methodName.startsWith("judge")) {
			return "select";
		} else if (methodName.startsWith("analysis")) {
			return "select";
		} else if (methodName.startsWith("insert")) {
			return "insert";
		} else if (methodName.startsWith("save")) {
			return "insert";
		} else if (methodName.startsWith("add")) {
			return "insert";
		} else if (methodName.startsWith("update")) {
			return "update";
		} else if (methodName.startsWith("modify")) {
			return "update";
		} else if (methodName.startsWith("edit")) {
			return "update";
		} else if (methodName.startsWith("delete")) {
			return "delete";
		} else if (methodName.startsWith("del")) {
			return "delete";
		}
		return "select";
	}

	private static Pair<String, String> decompose(String code) {
		code = StrUtil.trim(code);
		int index = -1;
		int indexLeft = -1;
		boolean find = false;
		for (int i = code.length() - 1; i >= 0; i--) {
			char ch = code.charAt(i);
			if (ch == ' ') {
				if (index == -1) {
					indexLeft = i;
					index = i;
					find = true;
				} else {
					indexLeft--;
				}
			} else if (find) {
				break;
			}
		}
		System.out.println("index=" + index);
		System.out.println("indexLeft=" + indexLeft);
		String key = code.substring(0, indexLeft);
		String value = code.substring(index + 1);
		Pair<String, String> pair = Pair.of(key, value);
		return pair;
	}

	private static List<String> paramList(String paramGroup) {
		if (paramGroup == null) {
			throw new RuntimeException("需要解析的参数不能为空!");
		}
		paramGroup = StrUtil.trim(paramGroup);
		List<String> list = new ArrayList<String>();
		if ("".equals(paramGroup)) {
			return list;
		}
		String[] split = paramGroup.split(",");
		for (int i = 0; i < split.length; i++) {
			String paramSpan = paramSpan(split[i]);
			list.add(paramSpan);
		}
		return list;
	}

	private static String paramSpan(String string) {
		string = StrUtil.trim(string);
		String body = string;
		int indexOf = string.indexOf("@Param");
		if (indexOf == -1) {
			body = string;
			int lastIndexOf = body.lastIndexOf(" ");
			if (lastIndexOf != -1) {
				String name = body.substring(lastIndexOf + 1);
				return name;
			}
		} else {
			if (string.startsWith("@Param")) {
				String span = StrUtil.removePrefix(string, "@Param");
				if (span.contains("(") && span.contains(")")) {
					int leftIndex = span.indexOf("(");
					int rightIndex = span.lastIndexOf(")");
					String name = span.substring(leftIndex + 1, rightIndex);
					name = StrUtil.trim(name);
					return removeQuotationMarks(name);
				}
			}
		}
		return null;
	}

	private static String removeQuotationMarks(String name) {
		name = StrUtil.trim(name);
		int leftIndex = name.indexOf("\"");
		int rightIndex = name.lastIndexOf("\"");
		if (leftIndex != -1 && rightIndex != -1) {
			return name.substring(leftIndex + 1, rightIndex);
		}
		return name;
	}

	private static String paramSpanType(String string) {
		string = StrUtil.trim(string);
		String body = string;
		int indexOf = string.indexOf("@Param");
		if (indexOf == -1) {
			body = string;
			int index = body.indexOf(" ");
			if (index != -1) {
				String name = body.substring(0, index);
				return name;
			}
		} else {
			if (string.startsWith("@Param")) {
				String span = StrUtil.removePrefix(string, "@Param");
				if (span.contains("(") && span.contains(")")) {
					int leftIndex = span.indexOf("(");
					int rightIndex = span.lastIndexOf(")");
					String nameSpan = span.substring(rightIndex + 1);
					nameSpan = StrUtil.trim(nameSpan);
					int index = nameSpan.indexOf(" ");
					if (index != -1) {
						String name = nameSpan.substring(0, index);
						return name;
					}
				}
			}
		}
		return null;
	}
}
